package tech.waterism.service.controller;

import tech.waterism.modelbase.PredictResult;
import com.alibaba.fastjson.JSON;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import tech.waterism.model.DHF;
import tech.waterism.service.cache.ModelTaskCache;
import tech.waterism.service.service.ModelCalculationService;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

/**
 * DHF(大伙房)模型控制器
 * 
 * <p>提供大伙房水文模型的REST API接口
 * 
 * @author 高宇
 * @since 1.0.0
 */
@Slf4j
@RestController
@RequestMapping("/api/model/dhf")
@Tag(name = "DHF模型", description = "大伙房水文模型 - 产汇流综合计算")
public class DHFModelController {

    @Autowired
    private ModelCalculationService calculationService;

    @Autowired
    private ModelTaskCache taskCache;

    @PostMapping("/calculate")
    @Operation(
            summary = "DHF模型同步计算",
            description = """
                    执行大伙房模型同步计算，等待计算完成后返回结果。
                    
                    **适用场景：** 小规模计算（<500时段）、实时性要求高
                    
                    **注意：** 计算期间会阻塞HTTP连接，如计算时间较长建议使用异步接口
                    
                    ## 输入参数说明
                    
                    ### 模型参数
                    - `DD`: 张力水容量系数 (0.5-0.8)
                    - `A`: 流域面积 (km²)
                    - `B`: 蓄水容量曲线指数 (0.1-0.4)
                    - `K0`: 自由水蓄水库出流系数 (0.3-0.7)
                    - 等其他参数...
                    
                    ### 时序输入
                    - `dt`: 时间序列 (格式: ["2010-07-30 08:00:00", ...])
                    - `rain`: 降雨量序列 (mm)
                    - `evaporation`: 蒸发量序列 (mm)
                    - `ES`: 月蒸发量 (mm)
                    
                    ### 初始状态
                    - `U0`, `S0`, `D0`: 初始水量状态
                    - `SA0`, `UA0`, `YA0`: 初始蓄水状态
                    
                    ## 输出结果
                    - `qSim`: 流量过程线 (m³/s)
                    - `rSim`: 径流分量 [[y0], [yu], [yL], [y]]
                    - `runoffSim`: 总径流深 (mm)
                    """
    )
    public ResponseEntity<?> calculate(@RequestBody Map<String, Object> inputData) {
        try {
            log.info("收到DHF模型计算请求");
            log.debug("输入参数: {}", JSON.toJSONString(inputData));

            // 创建模型实例
            DHF model = new DHF(inputData);

            // 执行计算
            model.predict();

            log.info("DHF模型计算完成");
            
            // 获取标准化输出对象（与output文件格式一致）
            tech.waterism.model.dto.ModelOutputSimple output = model.getLastOutput();
            log.debug("计算结果: {}", JSON.toJSONString(output));

            // 返回ModelOutputSimple对象（与output文件格式一致）
            return ResponseEntity.ok(output);

        } catch (IllegalArgumentException e) {
            log.error("DHF模型参数错误: {}", e.getMessage());
            return ResponseEntity.badRequest()
                    .body(Map.of(
                            "error", "参数错误",
                            "message", e.getMessage()
                    ));

        } catch (Exception e) {
            log.error("DHF模型计算失败", e);
            return ResponseEntity.internalServerError()
                    .body(Map.of(
                            "error", "计算失败",
                            "message", e.getMessage()
                    ));
        }
    }

    @PostMapping("/calculate/async")
    @Operation(
            summary = "DHF模型异步计算",
            description = """
                    提交DHF模型异步计算任务，立即返回任务ID。
                    
                    **适用场景：** 大规模计算（>500时段）、批量计算、对实时性要求不高
                    
                    **工作流程：**
                    1. 提交计算任务，立即返回任务ID
                    2. 使用任务ID轮询查询计算状态和结果
                    3. 计算完成后可获取结果
                    
                    **优势：**
                    - 不阻塞HTTP连接
                    - 支持高并发
                    - 客户端可自由选择查询时机
                    
                    ## 返回结果
                    - `taskId`: 任务ID（用于后续查询）
                    - `status`: 任务状态（SUBMITTED）
                    - `queryUrl`: 查询接口URL
                    """
    )
    public ResponseEntity<?> calculateAsync(@RequestBody Map<String, Object> inputData) {
        try {
            log.info("收到DHF模型异步计算请求");
            log.debug("输入参数: {}", JSON.toJSONString(inputData));

            // 生成任务ID
            String taskId = UUID.randomUUID().toString();

            // 提交异步计算任务
            CompletableFuture<tech.waterism.model.dto.ModelOutputSimple> future = calculationService.calculateDHFAsync(inputData);

            // 缓存任务
            taskCache.put(taskId, future, "DHF");

            log.info("DHF异步计算任务已提交 - taskId: {}", taskId);

            return ResponseEntity.accepted()
                    .body(Map.of(
                            "taskId", taskId,
                            "status", "SUBMITTED",
                            "message", "计算任务已提交，请使用taskId查询结果",
                            "queryUrl", "/api/model/dhf/task/" + taskId,
                            "modelName", "DHF"
                    ));

        } catch (IllegalArgumentException e) {
            log.error("DHF模型参数错误: {}", e.getMessage());
            return ResponseEntity.badRequest()
                    .body(Map.of(
                            "error", "参数错误",
                            "message", e.getMessage()
                    ));

        } catch (Exception e) {
            log.error("提交DHF异步任务失败", e);
            return ResponseEntity.internalServerError()
                    .body(Map.of(
                            "error", "提交失败",
                            "message", e.getMessage()
                    ));
        }
    }

    @GetMapping("/task/{taskId}")
    @Operation(
            summary = "查询异步计算任务状态",
            description = """
                    根据任务ID查询DHF模型异步计算任务的状态和结果。
                    
                    ## 任务状态
                    - `RUNNING`: 计算进行中
                    - `COMPLETED`: 计算完成，返回结果
                    - `FAILED`: 计算失败，返回错误信息
                    - `NOT_FOUND`: 任务不存在或已过期
                    
                    **注意：** 任务结果保留1年，过期后自动清理
                    """
    )
    public ResponseEntity<?> getTaskStatus(@PathVariable String taskId) {
        log.debug("查询任务状态 - taskId: {}", taskId);

        ModelTaskCache.TaskInfo taskInfo = taskCache.getTaskInfo(taskId);

        if (taskInfo == null) {
            log.warn("任务不存在 - taskId: {}", taskId);
            return ResponseEntity.status(404)
                    .body(Map.of(
                            "taskId", taskId,
                            "status", "NOT_FOUND",
                            "message", "任务不存在或已过期"
                    ));
        }

        CompletableFuture<tech.waterism.model.dto.ModelOutputSimple> future = taskInfo.getFuture();

        if (future.isDone()) {
            try {
                // 获取ModelOutputSimple结果
                tech.waterism.model.dto.ModelOutputSimple output = future.get();
                log.info("任务已完成 - taskId: {}", taskId);
                
                // 直接返回ModelOutputSimple对象（与output文件格式一致）
                return ResponseEntity.ok(output);

            } catch (Exception e) {
                log.error("获取任务结果失败 - taskId: {}", taskId, e);
                
                return ResponseEntity.ok(Map.of(
                        "taskId", taskId,
                        "status", "FAILED",
                        "modelName", taskInfo.getModelName(),
                        "error", e.getCause() != null ? e.getCause().getMessage() : e.getMessage()
                ));
            }
        } else {
            log.debug("任务运行中 - taskId: {}", taskId);
            
            return ResponseEntity.ok(Map.of(
                    "taskId", taskId,
                    "status", "RUNNING",
                    "modelName", taskInfo.getModelName(),
                    "createTime", taskInfo.getCreateTime().toString(),
                    "message", "计算进行中，请稍后查询"
            ));
        }
    }

    @GetMapping("/info")
    @Operation(
            summary = "获取DHF模型信息",
            description = "返回DHF模型的基本信息、参数说明等"
    )
    public ResponseEntity<?> getModelInfo() {
        // 使用HashMap构建参数Map（因为参数超过10个，不能使用Map.of）
        Map<String, String> parameters = new java.util.HashMap<>();
        parameters.put("S0", "表层蓄水容量 (mm) - 范围: 0-50");
        parameters.put("U0", "下层蓄水容量 (mm) - 范围: 0-90");
        parameters.put("D0", "地下水蓄水容量 (mm) - 范围: 70-160");
        parameters.put("K2", "下层下渗系数 - 范围: 0.2-0.8");
        parameters.put("KA", "前期净雨衰减系数 - 范围: 0.7-1");
        parameters.put("K", "表层出流系数 - 范围: 0.1-0.9");
        parameters.put("KW", "壤中流分配比例 - 范围: 0-1");
        parameters.put("G", "不透水面积比例 - 范围: 0-1");
        parameters.put("A", "蓄水空间分布参数 - 范围: 0-5");
        parameters.put("B", "下渗率形状系数 - 范围: 1-3");
        parameters.put("B0", "特征河长系数 - 范围: 0.5-2");
        parameters.put("K0", "汇流底宽指数 - 范围: 0-0.8");
        parameters.put("N", "地下与地表汇流时间比 - 范围: 2-6");
        parameters.put("L", "流域最大河长 (km)");
        parameters.put("DD", "地表汇流形状参数 - 范围: 0.5-4");
        parameters.put("CC", "地表汇流峰度参数 - 范围: 0.5-4");
        parameters.put("COE", "峰现时间参数 - 范围: 0-0.8");
        parameters.put("DDL", "地下汇流形状参数 - 范围: 0.5-4");
        parameters.put("CCL", "地下汇流峰度参数 - 范围: 0.5-4");
        parameters.put("F", "流域面积 (km²)");
        parameters.put("monthlyPET", "月潜在蒸散发量 (mm) - 12个月数据");
        
        return ResponseEntity.ok(Map.of(
                "modelName", "DHF",
                "modelFullName", "大伙房模型",
                "description", "流域产汇流综合计算模型",
                "version", "1.0.0",
                "initialState", Map.of(
                        "SA0", "初始表层蓄水量 (mm)",
                        "UA0", "初始下层蓄水量 (mm)",
                        "YA0", "初始前期影响雨量 (mm)"
                ),
                "parameters", parameters
        ));
    }
}

